use std::collections::{HashMap, HashSet};

use libp2p::{PeerId, kad, request_response::OutboundRequestId};
use serde::{Deserialize, Serialize};
use tokio::sync::{mpsc, oneshot};

use crate::network_api::P2PEventForApp;
use crate::{ProvidingContentId, network_core::P2pNetWorkError};

// re-export
pub(crate) use crate::network_core::network_core_impl::combined_behaviour::combined_behaviour_impl::{
    CombinedBehaviour, CombinedBehaviourEvent,
};

mod combined_behaviour_impl;
mod event_handler;

// for kademlia
pub(crate) struct KadEventMetaData {
    pub(super) pending_start_providing: HashMap<kad::QueryId, oneshot::Sender<()>>,
    pub(super) pending_get_providers: HashMap<kad::QueryId, oneshot::Sender<HashSet<PeerId>>>,
}

impl KadEventMetaData {
    pub(crate) fn new() -> Self {
        Self {
            pending_start_providing: Default::default(),
            pending_get_providers: Default::default(),
        }
    }
}

type PendingRequestFileMap =
    HashMap<OutboundRequestId, oneshot::Sender<Result<Vec<u8>, P2pNetWorkError>>>; // (request_id, response_sender)

pub(crate) struct RequestResponseEventMetaData {
    pub(super) event_sender_for_app: mpsc::Sender<P2PEventForApp>,
    pub(super) pending_request_file: PendingRequestFileMap, // (request_id, response_sender)
}

impl RequestResponseEventMetaData {
    pub(crate) fn new(event_sender_for_app: mpsc::Sender<P2PEventForApp>) -> Self {
        Self {
            event_sender_for_app,
            pending_request_file: Default::default(),
        }
    }
}

// Simple file exchange protocol
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct ContentRequest(pub(super) ProvidingContentId);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ContentResponse(pub(super) Result<Vec<u8>, String>);
